package com.starmark.gateway.auth.security.filter;


import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.starmark.core.framework.response.ErrorResponseData;
import com.starmark.core.framework.response.HttpCode;
import com.starmark.gateway.auth.security.config.GatewayProjectConfig;
import com.starmark.gateway.auth.security.config.IgnoreUrlConfig;
import com.starmark.gateway.auth.security.constants.GatewayConstant;
import com.starmark.gateway.auth.security.dto.SecurityUserInfo;
import com.starmark.gateway.auth.security.service.IAuthService;
import com.starmark.gateway.auth.security.service.IJwtTokenService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 请求url权限校验
 */

@WebFilter("/*")
@Slf4j
@Component
public class AccessGatewayFilter implements Filter, Ordered {

    @Autowired
    private IAuthService authService;
    @Autowired
    private GatewayProjectConfig gatewayProjectConfig;

    @Autowired
    private IJwtTokenService jwtTokenService;


    @Autowired
    private IgnoreUrlConfig ignoreUrlConfig;


    /**
     * 1.首先网关检查token是否有效，无效直接返回401，不调用签权服务
     * 2.调用签权服务器看是否对该请求有权限，有权限进入下一个filter，没有权限返回401
     *
     * @return
     */
    @SneakyThrows
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
        {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            HttpServletResponse response = (HttpServletResponse) servletResponse;
            String method = request.getMethod();
            String url = request.getServletPath();
            if (ignoreUrlConfig.isIgnoreUrl(url)) {
                //如果发现是css或者js文件，直接放行
                filterChain.doFilter(servletRequest, servletResponse);
                return;
            }
            log.debug("url:{},method:{}", url, method);
            String authentication = request.getHeader(GatewayConstant.X_CLIENT_TOKEN_USER);
            SecurityUserInfo securityUser = null;
            String userToken = "";
            //访问匿名网址时,如果有登陆帐号,也继续携带
            if (!StrUtil.isEmpty(authentication)) {
                userToken = jwtTokenService.getUserInfoByJwtToken(authentication);
                securityUser = JSONObject.parseObject(userToken, SecurityUserInfo.class);
            }

            //不需要网关签权的url
            if (authService.ignoreAuthentication(url, gatewayProjectConfig.getProjectCode())) {
                filterChain.doFilter(servletRequest, servletResponse);
                return;
            }


            // 如果请求未携带token信息, 直接跳出
            if (StrUtil.isEmpty(authentication) || jwtTokenService.isTokenExpired(authentication)) {
                log.debug("url:{},method:{}, 请求未携带token信息", url, method);
                unLogin(response);
                return;
            }

            if (authService.hasPermission(securityUser, url, method)) {
                //token续期
                if (jwtTokenService.shouldTokenRefresh(authentication, gatewayProjectConfig.getProjectCode())) {
                    String newToken = jwtTokenService.createJwtToken(userToken, gatewayProjectConfig.getProjectCode());
                    response.addHeader("x-auth-token", newToken);
                    response.addHeader("Access-Control-Expose-Headers", "*");
                }
                filterChain.doFilter(servletRequest, servletResponse);
            } else {
                unauthorized(response);
            }


    }

    /**
     * 没有登陆,跳到登陆页面
     *
     * @param response 交换系统
     * @return 没有登陆的JSON
     */
    @SneakyThrows
    private void unLogin(HttpServletResponse response) {
        response.setStatus(HttpStatus.OK.value());
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        response.getWriter().write(JSONObject.toJSONString(ErrorResponseData.newInstance(HttpStatus.FORBIDDEN.value(), "未登陆", gatewayProjectConfig.getLoginAddress())));

    }


    /**
     * 网关拒绝，返回401
     *
     * @param response 请求数据
     * @return 返回401
     */
    @SneakyThrows
    private void unauthorized(HttpServletResponse response) {
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        response.setContentType("application/json; charset=utf-8");
        response.getWriter().write(JSONObject.toJSONString(ErrorResponseData.newInstance(HttpCode.FORBIDDEN, "无权限")));

    }

    @Override
    public int getOrder() {
        return 1;
    }


}
